#ifndef ALMACENAMIENTO_H_
#define ALMACENAMIENTO_H_

#include <sstream>
#include <list>
#include <iostream>
#include "includes.h"


using namespace std;

namespace Toolkit
{

struct IndiceEspacio
{
    unsigned long int posicion;
    unsigned long int bytesDisponibles;

    bool operator <(const IndiceEspacio &otro) const
    {
        return this->bytesDisponibles < otro.bytesDisponibles;
    }

    bool operator ==(const IndiceEspacio &otro) const
    {
        return this->bytesDisponibles == otro.bytesDisponibles;
    }

    bool operator >(const IndiceEspacio &otro) const
    {
        return this->bytesDisponibles > otro.bytesDisponibles;
    }

};

class Almacenamiento
{
public:

	Almacenamiento (const unsigned long int &tamanoUnidad, const TipoSerializacion &tserializacion);
	virtual ~Almacenamiento() = 0;
	
	
	/**
	 * Inserta la serialización pasada en la primera posición vacía del archivo, 
	 * o al final de éste si no hay espacios. La posicion relativa donde se lo
	 * insertó es devuelta.
	 * Si el tamaño de la serialización es superior al permitido por el almacenamiento,
	 * se lanza una excepcion.
	 * */
	virtual unsigned long int guardarDato (const stringstream &serializacion);
	
	/**
	 * Inserta la serializacion pasada en la posicion indicada del archivo.
	 * Si el tamaño de la serialización es superior al permitido por el almacenamiento,
	 * se lanza una excepcion.
	 * */
	virtual void guardarDato (const stringstream &serializacion, const unsigned long int posicionDondeGuardar);
	
	/**
	 * Devuelve el elemento del archivo en la posicion especificada, en el sstream pasado, que debe estar
	 * abierto en el tipo de serializacion apropiada, y cuyo contenido será sobreescrito.
	 * Si la posición especificada está fuera del archivo, se lanza una excepcion.
	 * */
	virtual void recuperarDato (const unsigned long int posicionDondeGuardar, stringstream &resultado) const;
	
	/**
	 * Elimina el elemento en la posicion pasada del archivo y lo devuelve en el sstream pasado
	 * que debe estar abierto en el tipo de serializacion apropiada, y cuyo contenido será sobreescrito.
	 * Si la posición especificada está fuera del archivo, se lanza una excepcion.
	 * */
	virtual void eliminarDato (const long unsigned int posicionDondeEliminar, stringstream &resultado);
	
	unsigned long int getTamano () const;
	
	unsigned long int cantElementos() const;

	list<IndiceEspacio> getFragmentacion();

	void setFragmentacion(list<IndiceEspacio> &fragmentacion);

	unsigned long int espacioLibre() const;
		
protected:

	unsigned long int getTamano(const unsigned long int posicion) const;

	iostream* stream;
	unsigned long int tamanoUnidad;
	unsigned long int tamanoUnidadPrimera;
	unsigned long int elementos;
	unsigned long int offsetElementos;
	TipoSerializacion tserializacion;	
	list<unsigned long int> espacios;
	
	/**
	* Esta lista se mantiene para controlar la fragmentacion interna en las unidades del almacenamiento.
	* El mantenimiento debe ser realizado externamente al almacenamiento.
	* */
	list<IndiceEspacio> fragmentacion;

	/**
	 * Constructor que no realiza incializaciones (salvo la del tserializacion), delegandolas
	 * a las subclases.
	 * */
	Almacenamiento(const TipoSerializacion &tserializacion);	
	
};



}
#endif /* ALMACENAMIENTO_H_ */
